Skip to main content

[Day 16] Upload: 以假亂真的上傳

我們常常在交作業、交報告、分享檔案的時候需要上傳的步驟,那你有想過做一個好看的上傳動畫嗎? 今天我們就來實作Day #15,不會實際上傳檔案的好看動畫

CodePen: https://codepen.io/stevetanus/pen/vYjemrj


1. HTML

<div class="frame">
<div class="center">
<div class="bar"></div>
<div class="title">Drop file to upload</div>
<div class="dropzone">
<div class="content">
<img src="https://100dayscss.com/codepen/upload.svg" class="upload">
<span class="filename"></span>
<input type="file" class="input">
</div>
</div>
<img src="https://100dayscss.com/codepen/syncing.svg" class="syncing">
<img src="https://100dayscss.com/codepen/checkmark.svg" class="done">
<div class="upload-btn">Upload file</div>
</div>
</div>

.bar.title下方的進度條,.dropzone為上傳區,包含.content,裡面有上傳的圖樣img、上傳後的檔案名.filename.input可以點取方框上傳,最下面則有上傳中.syncing、上傳完成.done的圖樣和上傳檔案的按鈕.upload-btninput type='file'使產生上傳檔案的input tag。


2. SCSS(CSS)

.dropzone(上傳區)

.dropzone {
...
position: absolute;
display: table;
table-layout: fixed;
// dashed 為虛線border
border: 1px dashed #A4A4A4;
text-align: center;
overflow: hidden;

&.active{
opacity: 0;
display: none;
}
&.is-dragover{
border-color: #666;
background: #eee;
}

.content {
display: table-cell;
vertical-align: middle;
}
}

.dropzone為table排版,table-layout: fixed可以加快table的顯示速度,text-align: center讓圖片左右置中,.content中為table-cellvertical-align達到垂直置中。 加上is-dragover的class後,顏色會變暗,而加上.active則會消失移除。

.input

.input {
position: absolute;
// 使得整個.dropzone點擊都可以選擇檔案
top: 0;
right: 0;
bottom: 0;
left: 0;
opacity: 0;
}

.upload-btn(上傳按鈕)

.upload-btn{
...
background: #6ECE3B;
height: 40px;
text-align: center;
line-height: 40px; //line-height == height
box-shadow: 0 2px 0 0 #498C25;
cursor: pointer;
transition: all .2s ease-in-out;

&:hover {
box-shadow: 0 2px 0 0 #498C25, 0 2px 10px 0 #6ECE3B;
}
}

.upload-btnhover的時候,會有兩個陰影的效果。 在line-height等於height,行高等於元素高度時,文字上下置中。

.bar(進度條動畫)

.bar 
width: 300px;
background: #6ece3b;
transition: all 3s ease-out;
transform: scaleX(0);
transform-origin: 0 0;

&.active{
transform: scaleX(1) translate3d(0,0,0);
}
}

.bar加上.active會有3s從左到右延伸的動畫。

.syncing(上傳動畫)

.syncing {
...
opacity: 0;

&.active {
animation: syncing 3.2s ease-in-out;
}
}

@keyframes syncing {
0% {
transform: rotate(0deg);
}
10% {
opacity: 1;
}
90% {
opacity: 1;
}
100% {
transform: rotate(360deg);
opacity: 0;
}
}

上傳動畫在3.2秒完成,從透明到顯現並轉360度,再度消失。

.done(上傳完成)

.done {
...
opacity: 0;

&.active {
animation: done .5s ease-in 3.2s;
animation-fill-mode: both;
}
}

@keyframes done {
from {
opacity: 0;
}
to {
opacity: 1;
}
}

.done的動畫在3.2秒後開始,0.5秒結束,animation-fill-mode: both使.done最後的opacity停留在1。


3. JavaScript

let dropzone = document.querySelector('.dropzone');
dropzone.addEventListener("dragover", ()=>{
dropzone.classList.add("is-dragover");
});

dropzone.addEventListener("dragenter", ()=>{
dropzone.classList.add("is-dragover");
})

dropzone.addEventListener("dragend", ()=>{
dropzone.classList.remove("is-dragover");
})

dropzone.addEventListener("dragleave", () => {
dropzone.classList.remove("is-dragover");
});
dropzone.addEventListener("drop", () => {
dropzone.classList.remove("is-dragover");
});

這邊主要控制用拖拉的方式匯入檔案,dragoverdragenter事件時加入is-dragover,而在dragenddragleavedrop的時候移除,回復到原本的白色。

fileInput.addEventListener("change", () => {
fileName = document.querySelector(".filename");
for (let i = 0; i < fileInput.files.length; i++) {
fileName.innerHTML = `${fileInput.files[i].name}`;
}
upload.style.display = "none";
});

在上傳檔案時,使得fileInput改變,在.filename的span元素加入HTML: 上傳的檔案名字,顯示檔案名在上傳區,並且讓上傳檔案的照片(upload)移除。

button.addEventListener("click", () => {
startUpload();
});

function startUpload() {
// 一定要有檔案名字才會執行
if (!uploading && fileName != "") {
// 上傳中,使動畫只觸發一次
uploading = true;
button.innerHTML = "Uploading...";
dropzone.classList.add("active");
syncing.classList.add("active");
done.classList.add("active");
bar.classList.add("active");
timeOut = window.setTimeout(showDone, 3200);
}
}

function showDone() {
button.innerHTML = "Done";
}

點擊上傳按鈕觸發startUpload,改變上傳文字為"Uploading",加上元素們的.active開始動畫,setTimeout會在3200毫秒後再觸發showDone的動畫,讓上傳文字變為"Done"。


打包帶走(take away)

HTML

目標屬性
上傳檔案<input type="file">

CSS

目標屬性
虛線borderborder: 1px dashed
加快table的顯示速度width固定、table-layout: fixed
table-cell置中vertical-align達到垂直置中。
兩層陰影box-shadow: 0 2px 0 0 #498C25, 0 2px 10px 0 #6ECE3B;
進度條動畫width、fromscaleX(0)transform-origin: 0 0toscaleX(1)translate3d(0,0,0)

JavaScript

目標屬性
拖拉檔案效果dragoverdragenter相對於dragenddragleavedrop
元素加上文字button.innerHTML = "Uploading...";
setTimeout第二個函數為延遲時間

後記

好的,又是個星期五,大家辛苦了!!!小弟弟我最近在看求婚大作戰,對的沒錯就是那部經典日劇,我竟然現在才知道(˚Δ˚)b,小小戀歌怎麼可以那麼好聽~!